#ifndef ALGORITHM_H
#define ALGORITHM_H

//MattesMutualInformation Algorithm Headfile
#include "itkImageRegistrationMethod.h"
#include "itkTranslationTransform.h"
#include "itkMattesMutualInformationImageToImageMetric.h"
#include "itkLinearInterpolateImageFunction.h"
#include "itkRegularStepGradientDescentOptimizer.h"
#include "itkImage.h"

#include "itkNormalVariateGenerator.h" 

//others
#include "itkMeanSquaresImageToImageMetric.h"
#include "itkLinearInterpolateImageFunction.h"

#include "itkImageFileReader.h"
#include "itkImageFileWriter.h"

#include "itkResampleImageFilter.h"
#include "itkCastImageFilter.h"
#include "itkRescaleIntensityImageFilter.h"
#include "itkSubtractImageFilter.h"
#include <string.h>

#include "itkMutualInformationImageToImageMetric.h"
#include "itkGradientDescentOptimizer.h"
#include "itkNormalizeImageFilter.h"
#include "itkDiscreteGaussianImageFilter.h"
#include "itkCheckerBoardImageFilter.h"
#include "itkCommand.h"

#include "itkOrientedImage.h"
#include "itkCenteredRigid2DTransform.h"
#include "itkCenteredTransformInitializer.h"
#include "itkAmoebaOptimizer.h"
#include "itkOnePlusOneEvolutionaryOptimizer.h"

#include "itkQtUpdater.h"

#include <QString.h>
#include <Qobject.h>
#include <iostream>  
#include <sstream>  
using namespace std;  



class CommandIterationUpdate : public itk::Command 
{
public:
  typedef  CommandIterationUpdate   Self;
  typedef  itk::Command             Superclass;
  typedef itk::SmartPointer<Self>  Pointer;
  itkNewMacro( Self );

protected:
  CommandIterationUpdate() {};

public:

  typedef itk::RegularStepGradientDescentOptimizer     OptimizerType;
  typedef const OptimizerType                         *OptimizerPointer;

  void Execute(itk::Object *caller, const itk::EventObject & event)
  {
    Execute( (const itk::Object *)caller, event);
  }


  void Execute(const itk::Object * object, const itk::EventObject & event)
    {
    OptimizerPointer optimizer = 
                         dynamic_cast< OptimizerPointer >( object );

    if( ! itk::IterationEvent().CheckEvent( &event ) )
      {
      return;
      }
	QString * retVal = new QString;
	*(retVal) = 		
		QString::number(optimizer->GetCurrentIteration()) + QString(" = ") + 
		QString::number(optimizer->GetValue()) + QString(":") ;
	ostringstream o;
	o << optimizer->GetCurrentPosition();
	*(retVal) += QString::fromStdString(o.str());
	QtITKProcessUpdater::GetSingleInstance()->Update(
		retVal
		);
	/*
    std::cout << optimizer->GetCurrentIteration() << " = ";
    std::cout << optimizer->GetValue() << " : ";
    std::cout << optimizer->GetCurrentPosition() << std::endl;*/
  }
   
};


class CommandIterationUpdate1 : public itk::Command 
{
public:
  typedef  CommandIterationUpdate1   Self;
  typedef  itk::Command             Superclass;
  typedef  itk::SmartPointer<Self>  Pointer;

  itkNewMacro( Self );
protected:
  CommandIterationUpdate1() {};
public:
  typedef   itk::GradientDescentOptimizer     OptimizerType;
  typedef   const OptimizerType   *           OptimizerPointer;
  void Execute(itk::Object *caller, const itk::EventObject & event)
    {
    Execute( (const itk::Object *)caller, event);
    }

  void Execute(const itk::Object * object, const itk::EventObject & event)
    {
    OptimizerPointer optimizer = 
      dynamic_cast< OptimizerPointer >( object );
    if( ! itk::IterationEvent().CheckEvent( &event ) )
      {
      return;
      }
	/*
    std::cout << optimizer->GetCurrentIteration() << "   ";
    std::cout << optimizer->GetValue() << "   ";
    std::cout << optimizer->GetCurrentPosition() << std::endl;
	*/
	QString * retVal = new QString;
	*(retVal) = 		
		QString::number(optimizer->GetCurrentIteration()) + QString(" = ") + 
		QString::number(optimizer->GetValue()) + QString(":") ;
	ostringstream o;
	o << optimizer->GetCurrentPosition();
	*(retVal) += QString::fromStdString(o.str());
	QtITKProcessUpdater::GetSingleInstance()->Update(
		retVal
		);
    }
};

class CommandIterationUpdate2 : public itk::Command 
{
public:
  typedef  CommandIterationUpdate2   Self;
  typedef  itk::Command             Superclass;
  typedef itk::SmartPointer<Self>   Pointer;
  itkNewMacro( Self );
protected:
  CommandIterationUpdate2() { m_LastMetricValue = 0.0; };
public:
  typedef itk::OnePlusOneEvolutionaryOptimizer     OptimizerType;
  typedef   const OptimizerType *                  OptimizerPointer;

  void Execute(itk::Object *caller, const itk::EventObject & event)
    {
    Execute( (const itk::Object *)caller, event);
    }

  void Execute(const itk::Object * object, const itk::EventObject & event)
    {
      OptimizerPointer optimizer = 
        dynamic_cast< OptimizerPointer >( object );
      if( ! itk::IterationEvent().CheckEvent( &event ) )
        {
        return;
        }
      double currentValue = optimizer->GetValue();
      // Only print out when the Metric value changes
      if( vcl_fabs( m_LastMetricValue - currentValue ) > 1e-7 )
        { 

			QString * retVal = new QString;
			*(retVal) = 		
				QString::number(optimizer->GetCurrentIteration()) + QString(" = ") + 
				QString::number(currentValue) + QString(":") ;
			ostringstream o;
			o << optimizer->GetCurrentPosition();
			*(retVal) += QString::fromStdString(o.str());
			QtITKProcessUpdater::GetSingleInstance()->Update(
				retVal
				);
			/*
			std::cout << optimizer->GetCurrentIteration() << "   ";
			std::cout << currentValue << "   ";
			std::cout << optimizer->GetCurrentPosition() << std::endl;*/
			m_LastMetricValue = currentValue;
        }
    }
private:
  double m_LastMetricValue;
};

struct RegResultStruct
{
	std::string resultPath;
	std::string differenceBeforePath;
	std::string differenceAfterPath;
	std::string AlgorithmName;
	std::string processParamters;
	int TranslationAlongX;
	int TranslationAlongY;
	int numberOfIterations;
};

struct RegResultStruct2
{
	std::string filepath;
	int Angle;
	int CenterX;
	int CenterY;
	int TranslationX;
	int TranslationY;
	int numberOfIterations;
};

class MyRegistration
{
public:
	MyRegistration();
	~MyRegistration();

	RegResultStruct Algorithm1(std::string FixedImageString, std::string MovingImageString, std::string OutputString1, std::string OutputString2, std::string OutputString3);
	RegResultStruct Algorithm2(std::string FixedImageString, std::string MovingImageString, std::string OutputString1, std::string OutputString2, std::string OutputString3);
	RegResultStruct Algorithm3(std::string FixedImageString, std::string MovingImageString, std::string OutputString1, std::string OutputString2, std::string OutputString3);
	RegResultStruct ManualAlgorithm(std::string FixedImageString, std::string MovingImageString, int PointX, int PointY, int CenterX, int CenterY, int Angle, std::string OutputString1, std::string OutputString2, std::string OutputString3);

};

#endif